﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AMStudio.Common;
using System.Text.RegularExpressions;
using Microsoft.Practices.EnterpriseLibrary.ExceptionHandling;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Logging;
using AMStudio.DelegateDispather;
using System.IO.Ports;
using System.IO;

namespace AMStudio.Driver
{
    public class LightDriver : IAutomationDriver
    {
        protected ExceptionManager ExManager = EnterpriseLibraryContainer.Current.GetInstance<ExceptionManager>();

        private DelegateDispather.IEventClient eventClient;
        public DelegateDispather.IEventClient EventClient
        {
            get { return eventClient; }
            set { eventClient = value; }
        }
        private SerialPort hardwaredriver;
        private bool alreadyinitialized = false;
        private IExecuteReader result = new ExecuteReader(false);
        private String hardwareName = "ST1_LIGHT";
        public String HardwareName
        {
            get { return hardwareName; }
            set { hardwareName = value; }
        }
        private String hardwareEvent = "ST1_LIGHT_RET";
        private string templet = string.Empty;

        public String HardwareEvent
        {
            get { return hardwareEvent; }
            set { hardwareEvent = value; }
        }
        public virtual int ExecuteNonQuery(string command, params object[] parameters)
        {
            return -1;
        }
        public virtual IExecuteReader ExecuteReader(string command, params object[] parameters)
        {
            result.Success = false;
            try
            {
                switch (command)
                {
                    case "INIT":
                        {
                            if (alreadyinitialized)
                            {
                                result.Success = true;
                            }
                            IEventManager em = parameters[0] as IEventManager;
                            eventClient = new EventClient(em);
                            config = parameters[1] as  LightConfig;
                            this.hardwareEvent = config.HardwareEvent;
                            this.hardwareName = config.HardwareName;
                            //Logger.Write("Start to init hardware " + hardwareName);
                            //templet = File.ReadAllText(config.TempletFileName, System.Text.ASCIIEncoding.ASCII);
                            hardwaredriver = new SerialPort();
                            hardwaredriver.PortName = config.SerialPort.PortName;
                            hardwaredriver.BaudRate = config.SerialPort.BandRate;
                            hardwaredriver.Parity = config.SerialPort.Parity;
                            hardwaredriver.DataBits = config.SerialPort.DataBits;
                            hardwaredriver.StopBits = config.SerialPort.StopBits;
                            hardwaredriver.Handshake = config.SerialPort.HandShake;
                            hardwaredriver.WriteTimeout = config.SerialPort.WriteTimeout;
                            hardwaredriver.ReadTimeout = config.SerialPort.ReadTimeout;
                            //hardwaredriver.DataReceived += new SerialDataReceivedEventHandler(hardwaredriver_DataReceived);
                            hardwaredriver.Open();

                            RaiseEvent("CONNECT", true, null);
                            result.Success = true;
                            result.Result = true;
                            alreadyinitialized = true;

                        }
                        break;
                    case "LIGHT":
                        {
                            if (!alreadyinitialized)
                            {
                                break;
                            }

                            string channel = parameters[0].ToString();
                            int light = int.Parse(parameters[1].ToString());
                            string sRep = string.Empty;
                            SendCommandLight(light, channel, out sRep);
                            result.Success = true;
                            //result.Result = true;
                        }
                        break;
                    case "CHANNEL":
                        {
                            if (!alreadyinitialized)
                            {
                                break;
                            }

                            string channel = parameters[0].ToString();
                            bool onoroff = bool.Parse(parameters[1].ToString());
                            result.Success = true;
                            string sRep = string.Empty;
                            result.Result = SendCommandChannel(onoroff, channel, out sRep);
                            //result.Result = true;
                        }
                        break;
                    case "CONNECT_STATUS":
                        if (alreadyinitialized)
                        {
                            result.Success = true;
                            result.Result = true;
                        }
                        else
                        {
                            result.Success = false;
                            result.Result = false;
                        }
                        break;
                    case "EXIT":
                        if (hardwaredriver != null)
                        {
                            hardwaredriver.Close();
                        }
                        alreadyinitialized = false;
                        RaiseEvent("DISCONNECT", true, null);
                        break;
                }
            }
            catch (Exception ex)
            {
                ExManager.HandleException(ex, "Policy");
                alreadyinitialized = false;
                RaiseEvent("DISCONNECT", true, null);
                if (hardwaredriver != null)
                    hardwaredriver.Close();
            }
            return result;
        }


        public void WriteByte(byte[] bValue)
        {
            if (hardwaredriver == null)
            {
                return;
            }

            try
            {
                hardwaredriver.ReadExisting();
                hardwaredriver.DiscardInBuffer();
                hardwaredriver.DiscardOutBuffer();
                hardwaredriver.Write(bValue, 0, bValue.Length);
            }
            catch (Exception ex)
            {
                
            }
        }


        private void WriteCommand(String command)
        {
            String sum = String.Empty;

            command = "$" + command;
            sum = FCS(command);
            command = command + sum ;

            byte[] cmd_bytes = new byte[command.Length];
            for (int i = 0; i < command.Length; i++)
            {
                cmd_bytes[i] = Convert.ToByte(command[i]);
            }
            WriteByte(cmd_bytes);

        }


        private String FCS(String command)
        {
            String ret = String.Empty;
            char[] cmd_array = command.ToCharArray();
            int cnt = cmd_array.Length;

            byte[] cmd_bytes = new byte[cnt];
            for (int i = 0; i < cnt; i++)
            {
                cmd_bytes[i] = Convert.ToByte(cmd_array[i]);
            }
            byte lrc = LRC(cmd_bytes, cnt);
            return lrc.ToString("X2");
        }

        private byte LRC(byte[] byteValue, int nLen)
        {
            byte byteLRC = 0;
            int i = 0;

            while (i < nLen)
            {
                byteLRC = Convert.ToByte(Convert.ToUInt16(byteLRC) ^ Convert.ToUInt16(byteValue[i++]));
            }

            return byteLRC;
        }


        #region Command Related
        private bool SendCommandChannel(bool onoroff, string channel, out String sResponse)
        {
            String total_string = string.Empty;
            bool bRet = false;

            if (onoroff)
            {
                total_string = "1";
            }
            else
            {
                total_string = "2";
            }

            total_string = total_string + channel + "064";
            WriteCommand(total_string);
            sResponse = string.Empty;

            byte br = (byte)hardwaredriver.ReadByte();

            sResponse = Encoding.ASCII.GetString(new byte[] { br });

            if (sResponse =="$")
            {
                bRet = true;
            }
            else
            {
                bRet = false;

            }
            return bRet;
        }

        private bool SendCommandLight(int light, string channel, out String sResponse)
        {
            String total_string = string.Empty;
            bool bRet = false;

            total_string = "3" + channel + light.ToString("X3");

            WriteCommand(total_string);
            sResponse = string.Empty;

            byte br = (byte)hardwaredriver.ReadByte();

            sResponse = Convert.ToString(br);

            if (sResponse == "$")
            {
                bRet = true;
            }
            else
            {
                bRet = false;

            }
            return bRet;
        }
        #endregion

        private bool haveReceiveData = false;
        private string receivedData = string.Empty;
        private string myData = string.Empty;
        private LightConfig config = null;
        void hardwaredriver_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            receivedData += hardwaredriver.ReadExisting();
            if (receivedData.IndexOf(config.SerialPort.ETX) >= 0)
            {
                haveReceiveData = true;
                receivedData = receivedData.Replace(config.SerialPort.ETX, string.Empty);
                RaiseEvent("DATA_RECEIVE", true, receivedData);
                myData = receivedData;
                receivedData = string.Empty;
            }
        }

        public void RaiseEvent(string command, bool status, object value)
        {
            StationEventArgs arg = new StationEventArgs(hardwareName, command, status, value);
            eventClient.RaiseEvent(hardwareEvent, arg);
        }
    }
}
